package org.geom.surface.tubolar;

import java.util.ArrayList;

import org.geom.Maths;
import org.geom.Point3D;
import org.geom.Triangle;
import org.geom.Vector3D;
import org.geom.curve.ICurve;
import org.geom.surface.ISurface;

public class TubolarSurface implements ISurface {

	public ICurve curve;
	private float[] rotationMatrix;

	public ArrayList<Point3D> trunk_pos;
	public ArrayList<Vector3D> trunk_orientation;
	
	public ArrayList<Vector3D> tangents;
	public ArrayList<Vector3D> binormals;
	public ArrayList<Vector3D> normals;
	
	public TubolarSurface(ICurve curve) {
		this.curve = curve;
		sample();
	}


	private void sample() {
		ArrayList<Point3D> curves = curve.getPoints();
		ArrayList<Vector3D> tangents = getTangentPoints(curves);
		ArrayList<Vector3D> vectors = new ArrayList<Vector3D>();
		Vector3D initial_normal_vector = getTangent(tangents.get(0), tangents.get(1));
		vectors.add(initial_normal_vector);		
		

//		Vector3D t, t1, b, normalized_b, v, new_v;
//		float theta;
//		for(int i=0; i<tangents.size()-1; i++) {
//			v = vectors.get(0);
//			t = tangents.get(i);
//			t1 = tangents.get(i+1);
//			b = Vector3D.crossProduct(t, t1);
//			normalized_b = b.normalize();
//
//			if( normalized_b.x==0 && normalized_b.y==0 && normalized_b.z==0) {
//				new_v = new Vector3D(v);
//			} else {
//				b.x = b.x/normalized_b.x;
//				b.y = b.y/normalized_b.y;
//				b.z = b.z/normalized_b.z;
//
//				theta = (float) Math.acos(t.dot(t1));
//
//				rotation_matrix(b, theta, v);
//			}
//		}
		
//		Vector3D t1, t2, f1, f2_pos, f2, a, p;
//		float theta;
//		for(int i=0; i<tangents.size()-1; i++) {
//			f1 = vectors.get(i); //existing frame at t-1
//			t1 = tangents.get(i);
//			t2 = tangents.get(i+1);			
//			a = Vector3D.crossProduct(t1, t2);
//			
//			if (a.x==0 && a.y==0 && a.z==0) {
//				vectors.add(f1.duplicate());
//				continue;
//			}
//			
//			theta = (float) Math.acos( t2.dot(t1) );
//			f2 = f1.rotateAroundAxis(a, theta);
//			vectors.add(f2);
//
//			System.out.println(theta);
//		}
//		
//		this.trunk_orientation = vectors;
//		this.trunk_pos = curves;
		
		
		//non ne ho più. ultimo metodo, perse le speranze del parallel transport frame.
		
		//prima passata
		ArrayList<Vector3D> derivateI = getTangentPoints(curves);
		ArrayList<Vector3D> derivateII = getTangentPoints(derivateI);
		ArrayList<Vector3D> tangenti = derivateI;
		ArrayList<Vector3D> binormali = new ArrayList();
		for(int i=0; i<curves.size(); i++) {
			Vector3D dI = derivateI.get(i);
			Vector3D dII = derivateII.get(i);
			Vector3D b = Vector3D.crossProduct(dI, dII).normalize();
			binormali.add(b);
		}
		ArrayList<Vector3D> normali = new ArrayList();
		for(int i=0; i<curves.size(); i++) {
			Vector3D b = binormali.get(i);
			Vector3D t = tangenti.get(i);
			normali.add(Vector3D.crossProduct(b, t));
		}
		
		this.tangents = tangenti;
		this.binormals = binormali;
		this.normals = normali;
		this.trunk_pos = curves;
	}




//	private void rotation_matrix(Vector3D b, float angle, Vector3D v) {
//		float x = b.x,
//		y = b.y,
//		z = b.z;
//		float sinSave, cosSave, oneMinusCos;
//		float xx, yy, zz, xy, yz, zx, xs, ys, zs;
//
//		// If NULL vector passed in, this will blow up...
//		if(x == 0.0f && y == 0.0f && z == 0.0f)
//			return;
//
//		sinSave = (float)Maths.sin(angle);
//		cosSave = (float)Maths.cos(angle);
//		oneMinusCos = 1.0f - cosSave;
//
//		xx = x * x;
//		yy = y * y;
//		zz = z * z;
//		xy = x * y;
//		yz = y * z;
//		zx = z * x;
//		xs = x * sinSave;
//		ys = y * sinSave;
//		zs = z * sinSave;
//
//		rotationMatrix[0] = (oneMinusCos * xx) + cosSave;
//		rotationMatrix[4] = (oneMinusCos * xy) - zs;
//		rotationMatrix[8] = (oneMinusCos * zx) + ys;
//		rotationMatrix[12] = 0.0f;
//
//		rotationMatrix[1] = (oneMinusCos * xy) + zs;
//		rotationMatrix[5] = (oneMinusCos * yy) + cosSave;
//		rotationMatrix[9] = (oneMinusCos * yz) - xs;
//		rotationMatrix[13] = 0.0f;
//
//		rotationMatrix[2] = (oneMinusCos * zx) - ys;
//		rotationMatrix[6] = (oneMinusCos * yz) + xs;
//		rotationMatrix[10] = (oneMinusCos * zz) + cosSave;
//		rotationMatrix[14] = 0.0f;
//
//		rotationMatrix[3] = 0.0f;
//		rotationMatrix[7] = 0.0f;
//		rotationMatrix[11] = 0.0f;
//		rotationMatrix[15] = 1.0f;
//	}


	private ArrayList<Vector3D> getTangentPoints(ArrayList<? extends Point3D> points) {
		ArrayList<Vector3D> r = new ArrayList<Vector3D>();

		Point3D pre = new Point3D(0,0,0);
		for (Point3D p : points) {
			r.add( getTangent(pre, p) );			
		}

		return r;
	}


	private Vector3D getTangent(Point3D pre, Point3D p) {
		Vector3D t, normal_t;
		t = new Vector3D(0.1f, 0.1f, 0.1f);
		t.x = p.x-pre.x;
		t.y = p.y-pre.y;
		t.z = p.z-pre.z;

		normal_t = new Vector3D(t).normalize();

		t.x /= normal_t.x;
		t.y /= normal_t.y;
		t.z /= normal_t.z;

		return t;
	}







	@Override
	public void addFace(Point3D x, Point3D y, Point3D z) {
		// TODO Auto-generated method stub

	}

	@Override
	public void addFace(Triangle n) {
		// TODO Auto-generated method stub

	}

	@Override
	public ArrayList<Point3D> getPoints() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ArrayList<Triangle> getTriangles() {
		// TODO Auto-generated method stub
		return null;
	}

}
